package com.xinggq.gateway.service.impl;

import com.xinggq.auth.api.dto.login.AuthSafeUserInfoDTO;
import com.xinggq.common.CommonResult;
import com.xinggq.common.constant.AuthConstants;
import com.xinggq.gateway.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

/**
 * 令牌服务WebClient实现类
 * 使用WebClient替代Feign客户端，避免循环依赖
 *
 * @author xinggq
 * @since 2023-10-20
 */
@Slf4j
@Service
@Primary
public class WebClientTokenServiceImpl implements TokenService {

    private final WebClient webClient;
    private final String authServiceName;
    private final String authServicePath;
    private final String tokenValidatePath;

    public WebClientTokenServiceImpl(WebClient.Builder webClientBuilder,
                                    @Value("${auth.service.name:box-auth-center}") String authServiceName,
                                    @Value("${auth.service.path:/auth-center}") String authServicePath,
                                    @Value("${auth.token.validate.path:/auth/login/token/validate}") String tokenValidatePath) {
        this.webClient = webClientBuilder.build();
        this.authServiceName = authServiceName;
        this.authServicePath = authServicePath;
        this.tokenValidatePath = tokenValidatePath;
    }

    /**
     * 验证访问令牌并返回安全用户信息（响应式）
     * - 使用WebClient进行非阻塞调用
     * - 通过服务名进行负载均衡
     * - 处理异常并返回空结果
     */
    @Override
    public Mono<AuthSafeUserInfoDTO> validateToken(String token) {
        return webClient.get()
                .uri("lb://" + authServiceName + authServicePath + tokenValidatePath+"?token="+ token)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<CommonResult<AuthSafeUserInfoDTO>>() {})
                .mapNotNull(result -> {
                    if (result == null) {
                        log.warn("令牌验证失败，认证中心返回空");
                        return null;
                    }
                    if (!result.isSuccess()) {
                        log.warn("令牌验证失败，code={}, msg={}", result.getCode(), result.getMsg());
                        return null;
                    }
                    return result.getData();
                })
                .onErrorResume(e -> {
                    log.error("令牌验证异常", e);
                    return Mono.empty();
                });
    }
}